package cn.snmp.mutual.org.opennms.protocols.snmp;

import java.io.*;

import cn.snmp.mutual.org.opennms.protocols.snmp.asn1.AsnDecodingException;
import cn.snmp.mutual.org.opennms.protocols.snmp.asn1.AsnEncoder;
import cn.snmp.mutual.org.opennms.protocols.snmp.asn1.AsnEncodingException;

public class SnmpVarBind implements SnmpSyntax, Cloneable, Serializable {
    static final long serialVersionUID = 2328987288282447623L;
    private SnmpObjectId m_name;
    private SnmpSyntax m_value;
    public static final byte ASNTYPE = 48;

    public SnmpVarBind() {
        this.m_name = new SnmpObjectId();
        this.m_value = new SnmpNull();
    }

    public SnmpVarBind(final SnmpObjectId name) {
        this.m_name = (SnmpObjectId) name.duplicate();
        this.m_value = new SnmpNull();
    }

    public SnmpVarBind(final SnmpObjectId name, final SnmpSyntax value) {
        this.m_name = (SnmpObjectId) name.duplicate();
        this.m_value = value.duplicate();
    }

    public SnmpVarBind(final String name) {
        this.m_name = new SnmpObjectId(name);
        this.m_value = new SnmpNull();
    }

    public SnmpVarBind(final String name, final SnmpSyntax value) {
        this.m_name = new SnmpObjectId(name);
        this.m_value = value.duplicate();
    }

    public SnmpVarBind(final SnmpVarBind second) {
        this.m_name = (SnmpObjectId) second.m_name.duplicate();
        this.m_value = second.m_value.duplicate();
    }

    public SnmpObjectId getName() {
        return this.m_name;
    }

    public void setName(final SnmpObjectId name) {
        this.m_name = (SnmpObjectId) name.duplicate();
    }

    public void setName(final String name) {
        this.m_name = new SnmpObjectId(name);
    }

    public SnmpSyntax getValue() {
        return this.m_value;
    }

    public void setValue(final SnmpSyntax value) {
        this.m_value = value.duplicate();
    }

    public byte typeId() {
        return 48;
    }

    public int encodeASN(final byte[] buf, int offset, final AsnEncoder encoder) throws AsnEncodingException {
        final int begin = offset;
        offset = this.m_name.encodeASN(buf, offset, encoder);
        final int pivot;
        offset = (pivot = this.m_value.encodeASN(buf, offset, encoder));
        final int end = encoder.buildHeader(buf, offset, this.typeId(), pivot - begin);
        SnmpUtil.rotate(buf, begin, pivot, end);
        return end;
    }

    public int decodeASN(final byte[] buf, int offset, final AsnEncoder encoder) throws AsnDecodingException {
        final Object[] rVals = encoder.parseHeader(buf, offset);
        offset = (int) rVals[0];
        final byte asnType = (byte) rVals[1];
        final int asnLength = (int) rVals[2];
        if (buf.length - offset < asnLength) {
            throw new AsnDecodingException("Buffer underflow error");
        }
        if (asnType != this.typeId()) {
            throw new AsnDecodingException("Invalid ASN.1 type");
        }
        offset = this.m_name.decodeASN(buf, offset, encoder);
        this.m_value = SnmpUtil.getSyntaxObject(buf[offset]);
        if (this.m_value == null) {
            throw new AsnDecodingException("Unknown ASN.1 type");
        }
        offset = this.m_value.decodeASN(buf, offset, encoder);
        return offset;
    }

    public SnmpSyntax duplicate() {
        return new SnmpVarBind(this);
    }

    public Object clone() {
        return new SnmpVarBind(this);
    }

    @Override
    public String toString() {
        return "SNMP Varbind[ " + this.m_name.toString() + "(" + this.m_value.toString() + ") ]";
    }
}
